package org.example.aienglishapp.aspect.operationlog;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.example.aienglishapp.annotation.operationlog.Loggable;
import org.example.aienglishapp.entity.operationlog.OperationLog;
import org.example.aienglishapp.mapper.operationlog.OperationLogMapper;
import org.example.aienglishapp.util.operationlog.LogUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.LocalDateTime;
import java.util.Iterator;

@Aspect
@Component
public class OperationLogAspect {

    @Autowired
    private OperationLogMapper operationLogMapper;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Around("@annotation(loggableAnnotation)")
    public Object logOperation(ProceedingJoinPoint joinPoint, Loggable loggableAnnotation) throws Throwable {
        long startTime = System.currentTimeMillis(); // 记录开始时间
        OperationLog log = new OperationLog(); // 创建日志对象
        Object result = null;

        try {
            // 执行目标方法
            result = joinPoint.proceed();

            // 检查 result 的内容是否表示失败
            if (isErrorResult(result)) {
                log.setStatus("失败"); // 将状态设为失败
            } else {
                log.setStatus("成功"); // 否则为成功
            }

        } catch (Throwable throwable) {
            // 如果发生异常，也标记为失败
            log.setStatus("失败");
            throw throwable;
        } finally {
            // 记录日志信息
            log.setUsername(LogUtils.getCurrentUsername());
            log.setOperation(loggableAnnotation.value());
            log.setMethod(joinPoint.getSignature().toShortString());
            log.setParams(sanitizeParameters(joinPoint.getArgs()));
            log.setElapsedTime(System.currentTimeMillis() - startTime);
            log.setResult(result != null ? result.toString() : "null");
            log.setIpAddress(LogUtils.getClientIp());
            log.setCreateTime(LocalDateTime.now());

            // 保存日志到数据库
            operationLogMapper.insert(log);
        }

        return result;
    }

    private boolean isErrorResult(Object result) {
        if (result instanceof ResponseEntity) {
            ResponseEntity<?> responseEntity = (ResponseEntity<?>) result;
            return !responseEntity.getStatusCode().is2xxSuccessful();
        }
        return false;
    }

    //参数脱敏
    private String sanitizeParameters(Object[] args) {
        StringBuilder sanitizedParams = new StringBuilder("[");
        for (Object arg : args) {
            if (arg != null) {
                String sanitizedString = sanitizeObject(arg);
                sanitizedParams.append(sanitizedString).append(", ");
            } else {
                sanitizedParams.append("null, "); // 处理null参数
            }
        }
        if (sanitizedParams.length() > 1) {
            sanitizedParams.setLength(sanitizedParams.length() - 2); // 去掉最后的逗号和空格
        }
        sanitizedParams.append("]");
        return sanitizedParams.toString();
    }

    // 对象脱敏
    private String sanitizeObject(Object obj) {
        try {
            // 使用 Jackson 库将对象转换为 JSON 节点
            JsonNode node = objectMapper.valueToTree(obj);

            // 遍历节点并脱敏敏感字段
            sanitizeNode(node);

            // 将 JSON 节点转换为字符串
            return node.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return obj.toString();
        }
    }
    //节点脱敏
    private void sanitizeNode(JsonNode node) {
        if (node.isObject()) {
            ObjectNode objectNode = (ObjectNode) node;
            for (Iterator<String> it = objectNode.fieldNames(); it.hasNext(); ) {
                String fieldName = it.next();
                JsonNode fieldValue = objectNode.get(fieldName);

                if (fieldName.toLowerCase().contains("password")) {
                    // 如果字段名包含 "password"，则用星号替换
                    objectNode.put(fieldName, "*".repeat(fieldValue.asText().length()));
                } else if (fieldValue.isObject()) {
                    // 递归处理嵌套对象
                    sanitizeNode(fieldValue);
                }
            }
        }
    }

}